home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Very Best of Atari Inside
/
The Very Best of Atari Inside 1.iso
/
mint
/
mntlib43
/
mntlib
/
scanf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-14
|
10KB
|
548 lines
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include "lib.h"
/*
* %efg were loosing big time
* fixed ++jrb
* all floating conversion now done by atof. much is gained by this.
* ++jrb
*
* hacked to use stdarg by bm
*/
#ifndef __NO_FLOAT__
#define FLOATS 1
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define skip() \
while (isspace(c)) { charcnt++; c = (*get)(ip); if (c == EOF) goto done; }
#define TEN_MUL(X) ((((X) << 2) + (X)) << 1)
#if FLOATS
/* fp scan actions */
#define F_NADA 0 /* just change state */
#define F_SIGN 1 /* set sign */
#define F_ESIGN 2 /* set exponent's sign */
#define F_INT 3 /* adjust integer part */
#define F_FRAC 4 /* adjust fraction part */
#define F_EXP 5 /* adjust exponent part */
#define F_QUIT 6
#define NSTATE 8
#define FS_INIT 0 /* initial state */
#define FS_SIGNED 1 /* saw sign */
#define FS_DIGS 2 /* saw digits, no . */
#define FS_DOT 3 /* saw ., no digits */
#define FS_DD 4 /* saw digits and . */
#define FS_E 5 /* saw 'e' */
#define FS_ESIGN 6 /* saw exp's sign */
#define FS_EDIGS 7 /* saw exp's digits */
#define FC_DIG 0
#define FC_DOT 1
#define FC_E 2
#define FC_SIGN 3
/* given transition,state do what action? */
static const int fp_do[][NSTATE] = {
{F_INT,F_INT,F_INT,
F_FRAC,F_FRAC,
F_EXP,F_EXP,F_EXP}, /* see digit */
{F_NADA,F_NADA,F_NADA,
F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */
{F_QUIT,F_QUIT,
F_NADA,F_QUIT,F_NADA,
F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
{F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
F_ESIGN,F_QUIT,F_QUIT}, /* see sign */
};
/* given transition,state what is new state? */
static const int fp_ns[][NSTATE] = {
{FS_DIGS,FS_DIGS,FS_DIGS,
FS_DD,FS_DD,
FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */
{FS_DOT,FS_DOT,FS_DD,
}, /* see '.' */
{0,0,
FS_E,0,FS_E,
}, /* see e/E */
{FS_SIGNED,0,0,0,0,
FS_ESIGN,0,0}, /* see sign */
};
/* which states are valid terminators? */
static const int fp_sval[NSTATE] = {
0,0,1,0,1,1,1,1
};
#endif
#ifdef __STDC__
int _scanf(register FILE *ip, int (*get)(FILE *),
int (*unget)(int, FILE *), const char *_fmt, va_list args)
#else
int
_scanf(ip, get, unget, _fmt, args)
FILE *ip;
int (*get) __PROTO((FILE *));
int (*unget) __PROTO((int, FILE *));
const char *_fmt;
char **args;
#endif
{
register long n;
register int c, width, lval, sval, cnt = 0, charcnt = 1;
#if defined (PRINTF_LONGLONG) || defined (__STDC__)
register int llval = 0;
#endif
#ifdef PRINTF_LONGLONG
register long long lln;
#endif
int store, neg, base, endnull, c2;
register unsigned char *p = 0;
const unsigned char *fmt = (const unsigned char *) _fmt;
char delim[256], *q;
#if FLOATS
double fx;
char fbuf[128], *fbp;
int fstate, trans;
extern double atof __PROTO((const char *));
#endif
c = (*get)(ip);
while (*fmt)
{
if (*fmt == '%')
{
width = -1;
lval = FALSE;
#if defined (PRINTF_LONGLONG) || defined (__STDC__)
llval = FALSE;
#endif
sval = FALSE;
store = TRUE;
if (*++fmt == '*')
{
store = FALSE;
++fmt;
}
if (isdigit (*fmt)) /* width digit(s) */
{
width = *fmt++ - '0';
while (isdigit (*fmt))
width = TEN_MUL (width) + *fmt++ - '0';
}
fmtnxt:
switch(*fmt++)
{
case 'l': /* long data */
#ifdef PRINTF_LONGLONG
if (lval)
llval = TRUE;
#endif
lval = TRUE;
goto fmtnxt;
#ifdef __STDC__
case 'L': /* long double */
llval = TRUE;
goto fmtnxt;
#endif
case 'h': /* short data (for compatibility) */
sval = TRUE;
goto fmtnxt;
case 'i': /* any-base numeric */
base = 0;
neg = -1;
goto numfmt;
case 'b': /* unsigned binary, non-standard */
case 'B': /* non-standard */
base = 2;
neg = 0;
goto numfmt;
case 'o': /* unsigned octal */
case 'O': /* non-standard */
base = 8;
neg = 0;
goto numfmt;
case 'p': /* pointer */
lval = TRUE;
#ifdef PRINTF_LONGLONG
llval = FALSE;
#endif
/* fall through */
case 'x': /* unsigned hexadecimal */
case 'X': /* non-standard */
base = 16;
neg = 0;
goto numfmt;
case 'd': /* SIGNED decimal */
case 'D': /* non-standard */
base = 10;
neg = -1;
goto numfmt;
case 'u': /* unsigned decimal */
case 'U': /* non-standard */
base = 10;
neg = 0;
numfmt:
skip();
memset (delim, -1, sizeof (delim));
if (isupper(fmt[-1])) {
/* non-standard */
#ifdef PRINTF_LONGLONG
if (lval) llval = TRUE;
#endif
lval = TRUE;
}
n = 0;
#ifdef PRINTF_LONGLONG
lln = 0;
#endif
if (width == 0)
goto savnum;
if (!base)
{
if (c == '%') /* non-standard */
{
base = 2;
neg = 0;
goto skip1;
}
else if (c == '0')
{
if (--width == 0)
goto savnum;
charcnt++;
c = (*get)(ip);
if (c == EOF)
goto savnum;
if ((c != 'x')
&& (c != 'X'))
{
base = 8;
neg = 0;
for (c2 = 0; c2 < 8; c2++)
delim[c2 + '0'] = c2;
goto zeroin;
}
base = 16;
neg = 0;
goto skip1;
}
else
base = 10;
}
/* Check for 0x prefix */
if (base == 16 && c == '0')
{
if (--width == 0)
goto savnum;
charcnt++;
c = (*get) (ip);
if (c == EOF)
goto done;
if (c == 'x' || c == 'X')
goto skip1;
}
else if (neg == -1)
{
neg = c == '-';
if (neg || c == '+')
{
skip1:
if (--width == 0)
goto done;
charcnt++;
c = (*get)(ip);
if (c == EOF)
goto done;
}
}
/* delim[c] -> value of c or -1 */
p = (unsigned char *) "FEDCBAfedcba9876543210";
q = "\17\16\15\14\13\12\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0";
if (base < 16)
{
/* skip invalid digits */
p += 22 - base;
q += 22 - base;
}
while (*p)
delim[*p++] = *q++;
if (delim[c] == (char) -1)
goto done;
while (width--)
{
#ifdef PRINTF_LONGLONG
if (llval)
lln = (lln * base) + delim[c];
else
#endif
n = (n * base) + delim[c];
charcnt++;
c = (*get)(ip);
if (c == EOF)
break;
zeroin:
if (delim[c] == (char) -1)
break;
}
savnum:
if (store)
{
#ifdef __STDC__
p = va_arg(args, void *);
#else
p = ((unsigned char *) *args);
#endif
#ifdef PRINTF_LONGLONG
if (llval)
{
if (neg)
lln=-lln;
*((long long*) p) = lln;
}
else
#endif
{
if (neg)
n = -n;
if (lval)
*((long*) p) = n;
else if (sval)
*((short *) p) = (short) n;
else
*((int *) p) = (int) n;
++cnt;
}
}
break;
#if FLOATS
case 'E': /* non-standard */
case 'F':
case 'G':
lval = TRUE;
/* fall through */
case 'e': /* float */
case 'f':
case 'g':
skip();
memset (delim, -1, sizeof (delim));
for (c2 = '0'; c2 <= '9'; c2++)
delim[c2] = FC_DIG;
delim['.'] = FC_DOT;
delim['+'] = delim['-'] = FC_SIGN;
delim['e'] = delim['E'] = FC_E;
fstate = FS_INIT;
fbp = fbuf;
while (c != EOF && width--) {
trans = delim[c];
if (trans == (char) -1)
break;
if (fbp - fbuf + 1 < sizeof (fbuf))
*fbp++ = c;
if (fp_do[trans][fstate] == F_QUIT)
break;
fstate = fp_ns[trans][fstate];
charcnt++;
c = (*get)(ip);
}
*fbp = '\0';
if (!fp_sval[fstate])
goto done;
if (store) {
fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
#ifdef __STDC__
p = va_arg(args, void *);
#else
p = (unsigned char *) *args;
#endif
#ifdef __STDC__
/* partial support for long double */
#ifdef __M68881__ /* currently only with m68881 */
if (llval)
*(long double *) p = (long double) fx;
else
#endif
#endif
if (lval)
*((double *) p) = fx;
else
*((float *) p) = (float)fx;
++cnt;
}
break;
#endif
case 'n':
if (store) {
#ifdef __STDC__
p = va_arg(args, void *);
#else
p = (unsigned char *) *args;
#endif
/* Compensate for lookahead */
*((int *) p) = charcnt - 1;
}
break;
case 'c': /* character data */
if (width == -1)
width = 1;
endnull = FALSE;
memset (delim, 0, sizeof (delim));
if (c == EOF)
goto done;
goto strproc;
case '[': /* string w/ delimiter set */
endnull = TRUE;
/* get delimiters */
neg = FALSE;
if (*fmt == '^')
{
fmt++;
neg = TRUE;
}
memset (delim, !neg, sizeof (delim));
if ((*fmt == ']') || (*fmt == '-'))
{
delim[*fmt++] = neg;
}
while (c2 = *fmt++, c2 != ']')
{
if (c2 == '\0')
break;
if (*fmt == '-' && fmt[1] && fmt[1] != ']')
{
while (c2 <= fmt[1])
delim[c2++] = neg;
fmt += 2;
}
else
delim[c2] = neg;
}
goto strproc;
case 's': /* string data */
skip();
memset (delim, 0, sizeof (delim));
delim['\t'] = 1;
delim['\n'] = 1;
delim['\v'] = 1;
delim['\f'] = 1;
delim['\r'] = 1;
delim[' '] = 1;
endnull = TRUE;
strproc:
/* process string */
#ifdef __STDC__
if (store)
p = va_arg(args, void *);
#else
p = ((unsigned char *) *args);
#endif
/* if the 1st char fails, match fails */
if (width)
{
if (c == EOF || delim[c])
{
if (endnull)
if (store)
*p = '\0';
goto done;
}
}
for (;;) /* FOREVER */
{
if (store)
*p++ = c;
charcnt++;
c = (*get)(ip);
if (c == EOF || --width == 0)
break;
if (delim[c])
break;
}
if (store)
{
if (endnull)
*p = '\0';
++cnt;
}
break;
case '%':
--fmt;
goto cmatch;
default:
goto done;
}
}
else if (isspace(*fmt)) /* skip whitespace */
{
fmt++;
skip();
}
else
{ /* normal match char */
cmatch:
if (c != *fmt++)
goto done;
charcnt++;
c = (*get)(ip);
}
#ifdef __STDC__
/* nothing to do */
#else
if (store)
args++;
#endif
}
done: /* end of scan */
if (c != EOF)
(*unget) (c, ip);
if (c == EOF && cnt == 0)
return(EOF);
return(cnt);
}